// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ************************************************************************* //
//                           avtWellBorePlot.C                               //
// ************************************************************************* //

#include <avtWellBorePlot.h>

#include <avtColorTables.h>
#include <avtWellBoreNameMapper.h>
#include <avtLevelsLegend.h>
#include <avtLevelsMapper.h>
#include <avtLookupTable.h>
#include <avtWellBoreFilter.h>

#include <InvalidColortableException.h>

#include <string>

// ****************************************************************************
//  Method: avtWellBorePlot constructor
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
//  Modifications:
//      Eric Brugger, Mon Nov 10 09:14:52 PST 2008
//      Added the ability to display well bore names and stems.
//
// ****************************************************************************

avtWellBorePlot::avtWellBorePlot()
{
    WellBoreFilter = new avtWellBoreFilter(atts);

    levelsMapper   = new avtLevelsMapper;
    levelsLegend   = new avtLevelsLegend;
    levelsLegend->SetTitle("Well Bore");
    levelsLegend->SetVarRangeVisibility(0);
    levelsLegend->SetReverseOrder(true);
    avtLUT         = new avtLookupTable;

    decoMapper     = new avtWellBoreNameMapper();

    //
    // This allows the legend to be reference counted so the behavior can
    // still access it after the plot is deleted.  The legend cannot be
    // reference counted all of the time since we need to know that it is a
    // LevelsLegend.
    //
    levLegendRefPtr = levelsLegend;
}


// ****************************************************************************
//  Method: avtWellBorePlot destructor
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
//  Modifications:
//      Eric Brugger, Mon Nov 10 09:14:52 PST 2008
//      Added the ability to display well bore names and stems.
//
// ****************************************************************************

avtWellBorePlot::~avtWellBorePlot()
{
    if (levelsMapper != NULL)
    {
        delete levelsMapper;
        levelsMapper = NULL;
    }
    if (WellBoreFilter != NULL)
    {
        delete WellBoreFilter;
        WellBoreFilter = NULL;
    }
    if (decoMapper != NULL)
    {
        delete decoMapper;
        decoMapper = NULL;
    }
    if (avtLUT != NULL)
    {
        delete avtLUT;
        avtLUT = NULL;
    }

    //
    // Do not delete the levelsLegend since it is being held by
    // levLegendRefPtr.
    //
}


// ****************************************************************************
//  Method:  avtWellBorePlot::Create
//
//  Purpose:
//    Call the constructor.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
// ****************************************************************************

avtPlot*
avtWellBorePlot::Create()
{
    return new avtWellBorePlot;
}


// ****************************************************************************
//  Method: avtWellBorePlot::GetMapper
//
//  Purpose:
//      Gets a mapper for this plot, it is actually a variable mapper.
//
//  Returns:    The variable mapper typed as its base class mapper.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
// ****************************************************************************

avtMapperBase *
avtWellBorePlot::GetMapper(void)
{
    return levelsMapper;
}


// ****************************************************************************
//  Method: avtWellBore::GetDecorationsMapper
//
//  Purpose:
//      Gets a decorations mapper for this plot, in this case the
//      labeled curve mapper.
//
//  Returns:    The labeled curve mapper typed as its base class mapper.
//
//  Programmer: Eric Brugger
//  Creation:   November 10, 2008
//
// ****************************************************************************

avtDecorationsMapper *
avtWellBorePlot::GetDecorationsMapper(void)
{
    return decoMapper;
}


// ****************************************************************************
//  Method: avtWellBorePlot::ApplyOperators
//
//  Purpose:
//      Applies the operators associated with a WellBore plot.  
//      The output from this method is a query-able object.
//
//  Arguments:
//      input   The input data object.
//
//  Returns:    The data object after the WellBore plot has been applied.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
// ****************************************************************************

avtDataObject_p
avtWellBorePlot::ApplyOperators(avtDataObject_p input)
{
    WellBoreFilter->SetInput(input);
    return WellBoreFilter->GetOutput();
}


// ****************************************************************************
//  Method: avtWellBorePlot::ApplyRenderingTransformation
//
//  Purpose:
//      Applies the rendering transformation associated with a WellBore plot.  
//
//  Arguments:
//      input   The input data object.
//
//  Returns:    The data object after the WellBore plot has been applied.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
// ****************************************************************************

avtDataObject_p
avtWellBorePlot::ApplyRenderingTransformation(avtDataObject_p input)
{
    return input;
}


// ****************************************************************************
//  Method: avtWellBorePlot::CustomizeBehavior
//
//  Purpose:
//      Customizes the behavior as appropriate for a WellBore plot.  This
//      includes behavior like shifting towards or away from the screen.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
// ****************************************************************************

void
avtWellBorePlot::CustomizeBehavior(void)
{
    levelsLegend->SetLookupTable(avtLUT->GetLookupTable());

    if (atts.GetNWellBores() > 0)
    {
        levelsLegend->SetLevels(atts.GetWellNames());
        levelsLegend->SetColorBarVisibility(1);
        levelsLegend->SetMessage(NULL);
    }
    else
    {
        levelsLegend->SetColorBarVisibility(0);
        levelsLegend->SetMessage("No well bores");
    }

    behavior->SetLegend(levLegendRefPtr);
    behavior->SetShiftFactor(0.6);
}


// ****************************************************************************
//  Method: avtWellBorePlot::CustomizeMapper
//
//  Purpose:
//      A hook from the base class that allows the plot to change its mapper
//      based on the dataset input. 
//
//  Arguments:
//      doi     The data object information.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
// ****************************************************************************

void
avtWellBorePlot::CustomizeMapper(avtDataObjectInformation &doi)
{
}


// ****************************************************************************
//  Method: avtWellBorePlot::SetAtts
//
//  Purpose:
//      Sets the atts for the WellBore plot.
//
//  Arguments:
//      atts    The attributes for this WellBore plot.
//
//  Programmer: brugger -- generated by xml2avt
//  Creation:   Wed Aug 27 14:59:19 PST 2008
//
//  Modifications:
//      Eric Brugger, Mon Nov 10 09:14:52 PST 2008
//      Added the ability to display well bore names and stems.
//
// ****************************************************************************

void
avtWellBorePlot::SetAtts(const AttributeGroup *a)
{
    const WellBoreAttributes *newAtts = (const WellBoreAttributes *)a;

    needsRecalculation = atts.ChangesRequireRecalculation(*newAtts);

    atts = *newAtts;

    if (WellBoreFilter != NULL)
        WellBoreFilter->SetAttributes(*newAtts);

    if (newAtts->GetNWellBores() == 0)
        return;

    SetColors();

    SetLegend(atts.GetLegendFlag());
    SetLineWidth(atts.GetWellLineWidth());

    decoMapper->SetScale(atts.GetWellNameScale());
    decoMapper->SetLabelVisibility(true);
}


// ****************************************************************************
//  Method: avtWellBorePlot::SetColors
//
//  Purpose:
//      Sets the plots colors.
//
//  Programmer: Eric Brugger
//  Creation:   October 1, 2008
//
//  Modifications:
//    Kathleen Bonnell, Mon Jan 17 18:19:07 MST 2011
//    Retrieve invertColorTable flag and send to color table.
//
//    Kathleen Biagas, Thu Oct 16 09:12:03 PDT 2014
//    Send 'needsRecalculation' flag to levelsMapper when setting colors.
//
// ****************************************************************************

void
avtWellBorePlot::SetColors()
{
    if (atts.GetColorType() == WellBoreAttributes::ColorBySingleColor)
    {
        const ColorAttribute ca = atts.GetSingleColor();
        ColorAttributeList cal;
        cal.AddColors(atts.GetSingleColor());
        avtLUT->SetLUTColorsWithOpacity(ca.GetColor(), 1);
        levelsMapper->SetColors(cal, needsRecalculation);
    }
    else if (atts.GetColorType() == WellBoreAttributes::ColorByMultipleColors)
    {
        const ColorAttributeList &cal = atts.GetMultiColor();
        unsigned char *colors = new unsigned char[atts.GetNWellBores() * 4];
        unsigned char *cptr = colors;
        for(int i = 0; i < atts.GetNWellBores(); i++)
        {
            *cptr++ = (char)cal[i].Red();
            *cptr++ = (char)cal[i].Green();
            *cptr++ = (char)cal[i].Blue();
            *cptr++ = (char)cal[i].Alpha();
        }

        avtLUT->SetLUTColorsWithOpacity(colors, atts.GetNWellBores());
        levelsMapper->SetColors(cal, needsRecalculation);

        delete [] colors;
    }
    else // ColorByColorTable
    {
        ColorAttributeList cal(atts.GetMultiColor());
        unsigned char *colors = new unsigned char[atts.GetNWellBores() * 4];
        unsigned char *cptr = colors;
        avtColorTables *ct = avtColorTables::Instance();
        const int opacity = 255;

        //
        // Detect if we're using the default color table or a color table
        // that does not exist anymore.
        //
        std::string ctName(atts.GetColorTableName());
        if(ctName == "Default")
            ctName = std::string(ct->GetDefaultDiscreteColorTable());
        else if(!ct->ColorTableExists(ctName.c_str()))
        {
            delete [] colors;
            EXCEPTION1(InvalidColortableException, ctName);
        }

        bool invert = atts.GetInvertColorTable();

        //
        // Add a color for each subset name.
        //
        if(ct->IsDiscrete(ctName.c_str()))
        {
            // The CT is discrete, get its color color control points.
            for(int i = 0; i < atts.GetNWellBores(); ++i)
            {
                unsigned char rgb[3] = {0,0,0};
                ct->GetControlPointColor(ctName.c_str(), i, rgb, invert);
                *cptr++ = rgb[0];
                *cptr++ = rgb[1];
                *cptr++ = rgb[2];
                *cptr++ = opacity;

                cal[i].SetRgba(rgb[0], rgb[1], rgb[2], opacity);
            }
        }
        else
        {
            // The CT is continuous, sample the CT so we have a unique color
            // for each element.
            unsigned char *rgb = ct->GetSampledColors(ctName.c_str(),
                                                      atts.GetNWellBores(),
                                                      invert);
            if(rgb)
            {
                for(int i = 0; i < atts.GetNWellBores(); ++i)
                {
                     int j = i * 3;
                     *cptr++ = rgb[j];
                     *cptr++ = rgb[j+1];
                     *cptr++ = rgb[j+2];
                     *cptr++ = opacity;

                     cal[i].SetRgba(rgb[j], rgb[j+1], rgb[j+2], opacity);
                }
                delete [] rgb;
            }
        }

        avtLUT->SetLUTColorsWithOpacity(colors, atts.GetNWellBores());
        levelsMapper->SetColors(cal, needsRecalculation);

        delete [] colors;
    }
}


// ****************************************************************************
//  Method: avtWellBorePlot::SetLegend
//
//  Purpose:
//      Sets a flag indicating if the legend should be displayed for the
//      WellBore plot.
//
//  Arguments:
//      legendOn Flag indicating if the legend should be displayed for
//               this WellBore plot.
//
//  Programmer: Eric Brugger
//  Creation:   October 1, 2008
//
// ****************************************************************************

void
avtWellBorePlot::SetLegend(bool legendOn)
{
    if (legendOn)
    {
        levelsLegend->LegendOn();
    }
    else
    {
        levelsLegend->LegendOff();
    }
}


// ****************************************************************************
//  Method: avtWellBorePlot::SetLineWidth
//
//  Purpose:
//      Sets the line width for the WellBore plot.
//
//  Arguments:
//      lw      The line width for this WellBore plot.
//
//  Programmer: Eric Brugger
//  Creation:   October 1, 2008
//
// ****************************************************************************

void
avtWellBorePlot::SetLineWidth(int lw)
{
    levelsMapper->SetLineWidth(Int2LineWidth(lw));
}

